#pragma once
#include <iostream>
#include <string>
#include <pthread.h>
#include <unistd.h>
#include <cstdarg>
#include <fstream>
#include <cstring>
#include <ctime>
enum
{
    DEBUG = 1,
    INFO,
    WARINIG,
    ERROR,
    FATAL
};

std::string LevelToString(int level)
{
    switch (level)
    {
    case DEBUG:
    {
        return "DEBUG"; // 构造临时对象
        break;
    }

    case INFO:
    {
        return "INFO";
        break;
    }
    case WARINIG:
    {
        return "WARING";
        break;
    }
    case ERROR:
    {
        return "ERROR";
        break;
    }
    case FATAL:
    {
        return "FATAL";
        break;
    }
    default:
    {
        return "UNKNOW";
        break;
    }
    }
}
inline std::string GetNow()
{
    time_t now = time(nullptr);
    struct tm *curr_time = localtime(&now);
    char buff[128];
    snprintf(buff, sizeof(buff), "%d-%d-%02d %02d:%02d:%02d",
             curr_time->tm_year + 1900,
             curr_time->tm_mon + 1,
             curr_time->tm_mday,
             curr_time->tm_hour,
             curr_time->tm_min,
             curr_time->tm_sec);
    return buff;
}
class LogMessage
{
public:
    LogMessage() {}
    ~LogMessage() {}
    std::string _level;
    pid_t _id;
    std::string _filename;
    int _line;
    std::string _time;
    std::string _message;
};

const std::string gfile = "./log.txt";
#define SCREEN 1
#define FILEs 2
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
class Log
{
private:
    void FlushToScreen(LogMessage &lg)
    {
        printf("[%s]:[%s][%d][%d][%s][%s]\n", lg._level.c_str(), lg._filename.c_str(), lg._line, lg._id, lg._message.c_str(), lg._time.c_str());
    }
    void FlushToFile(LogMessage &lg)
    {
        std::ofstream out(_file, std::ios::app); // 追加方式打开
        if (!out.is_open())
            return; // 打开失败，直接返回
        char buff[1024];
        snprintf(buff, sizeof(buff), "[%s]:[%s][%d][%d][%s][%s]\n", lg._level.c_str(), lg._filename.c_str(), lg._line, lg._id, lg._message.c_str(), lg._time.c_str());
        out.write(buff, strlen(buff));
        out.close(); // 关闭文件
    }
    // 需要保护临界资源
    void Flush(LogMessage &lg)
    {
        // 加锁
        switch (_type)
        {
        case SCREEN:
        {
            pthread_mutex_lock(&mutex);
            FlushToScreen(lg);
            pthread_mutex_unlock(&mutex);
            break;
        }

        case FILEs:
        {
            pthread_mutex_lock(&mutex);

            FlushToFile(lg);

            pthread_mutex_unlock(&mutex);
            break;
        }
        }
    }

public:
    // 默认往屏幕打印
    Log(const std::string &s = gfile) : _type(SCREEN), _file(s)
    {
    }
    void Enable(int type)
    {
        _type = type;
    }
    // 构建一条message
    void logMessage(std::string filename, int line, int level, const char *format, ...)
    {
        LogMessage lg;
        lg._filename = filename;
        lg._id = getpid();
        lg._line = line;
        lg._level = LevelToString(level);
        lg._time = GetNow();
        va_list ap;
        va_start(ap, format);
        char buff[1024];
        vsnprintf(buff, sizeof(buff), format, ap);
        va_end(ap);
        lg._message = buff;

        // 打印日志
        Flush(lg);
    }
    ~Log()
    {
    }

private:
    int _type;         // 往哪里打印
    std::string _file; // 往文件打印的文件名
};
Log lg;
#define LOG(Level, Format, ...)                                          \
    do                                                                   \
    {                                                                    \
        lg.logMessage(__FILE__, __LINE__, Level, Format, ##__VA_ARGS__); \
    } while (0)
#define EnableScreen()     \
    do                     \
    {                      \
        lg.Enable(SCREEN); \
    } while (0)

#define EnableFile()     \
    do                   \
    {                    \
        lg.Enable(FILEs); \
    } while (0)
